package per.wsj.httplib.ok

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.handleCoroutineException
import kotlinx.coroutines.withContext
import okhttp3.MediaType
import okhttp3.Request
import okhttp3.RequestBody
import org.json.JSONObject
import per.wsj.commonlib.utils.LogUtil
import per.wsj.httplib.ok.exception.ExceptionUtils
import per.wsj.httplib.ok.exception.MyException
import java.lang.reflect.Type

object HttpUtils {

    @Deprecated("use get()")
    suspend inline fun <reified T> execGet(
        url: String, crossinline getResult: (T) -> Unit
    ) {
        val type = object : TypeToken<T>() {}.type

        val request = Request.Builder()
            .url(url)
            .build()
        OkHttpUtils.mClient.newCall(request).execute().use { response ->
            val body = response.body()?.string() ?: throw MyException("数据为空")
            val jsonObject = JSONObject(body)
            val code = jsonObject.get("errorCode")
            when (code) {
                0 -> {
                    val data = jsonObject.get("data").toString()
                    withContext(Dispatchers.Main) {
                        getResult(Gson().fromJson(data, type))
                    }
                }
                444 -> {
                    throw MyException("异常xxx...")
                }
                else -> {
                    throw MyException("未知异常：$code")
                }
            }
        }
    }

    suspend inline fun <T> get(url: String, noinline error: ((String) -> Unit)? = null): T? {
        val type = object : TypeToken<T>() {}.type
        return execRequest(url, type, error)
    }

    suspend fun <T> execRequest(
        url: String, type: Type, error: ((String) -> Unit)?
    ): T? {
        val request = Request.Builder()
            .url(url)
            .build()
        try {
            OkHttpUtils.mClient.newCall(request).execute().use { response ->
                val body = response.body()?.string() ?: throw MyException("数据为空")
                val jsonObject = JSONObject(body)
                val code = jsonObject.get("errorCode")
                when (code) {
                    0 -> {
                        val data = jsonObject.get("data").toString()
//                    val msg = jsonObject.get("errorMsg").toString()
                        return Gson().fromJson(data, type)
                    }
                    444 -> {
                        throw MyException("异常xxx...")
                    }
                    else -> {
                        throw MyException("未知异常：$code")
                    }
                }
            }
        } catch (e: Throwable) {
            if (error != null) {
                error(ExceptionUtils.parseException(e))
                return null
            } else {
                throw e
            }
        }
    }

    /********************************************post************************************************/
    suspend inline fun <T> post(
        url: String,
        param: HashMap<String, Any>,
        noinline error: ((String) -> Unit)? = null
    ): T? {
        val type = object : TypeToken<T>() {}.type
        return execPost(url, param, type, error)
    }

    suspend fun <T> execPost(
        url: String, param: HashMap<String, Any>, type: Type, error: ((String) -> Unit)?
    ): T? {
        val json = Gson().toJson(param)
        val requestBody = RequestBody.create(
            MediaType.parse("application/json; charset=utf-8"),
            json
        )
        val request = Request.Builder()
            .url(url)
            .method("POST", requestBody)
            .build()
        try {
            OkHttpUtils.mClient.newCall(request).execute().use { response ->
                LogUtil.e("code: " + response.code())
                var res = response.body()?.string()
                val body = res ?: throw MyException("数据为空")
                val jsonObject = JSONObject(body)
                val code = jsonObject.get("code")
                when (code) {
                    "200" -> {
                        val data = jsonObject.get("result").toString()
                        return Gson().fromJson(data, type)
                    }
                    else -> {
                        throw MyException("未知异常：$code")
                    }
                }
            }
        } catch (e: Throwable) {
            if (error != null) {
                error(ExceptionUtils.parseException(e))
                return null
            } else {
                throw e
            }
        }
    }
}